#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <sys/resource.h>
#include <signal.h>

void daemonize(const char *cmd)
{
    int i, fd0, fd1, fd2;
    pid_t pid;
    struct rlimit rl;
    struct sigaction sa;

    /* clear file creation mask */
    umask(0);

    /* get maximum number of file descriptors */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
    {
        fprintf(stderr, "%s: can't get file limit\n", cmd);
        exit(0);
    }

    /* become a session leader to lose controlling TTY */
    if ((pid = fork()) < 0)
    {
        fprintf(stderr, "%s: can't fork\n", cmd);
        exit(0);
    }
    else if (pid != 0)
        exit(0);
    setsid();

    /* ensure future opens won't allocate controlling TTY */
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
    {
        fprintf(stderr, "%s: can't ignore SIGHUP\n", cmd);
        exit(0);
    }

    if ((pid = fork()) < 0)
    {
        fprintf(stderr, "%s: can't fork\n", cmd);
        exit(0);
    }
    else if (pid != 0)
        exit(0);

    /* change the current working directory to the root so won't 
     * prevent file systems from being unmounted */
    if  (chdir("/") < 0)
    {
        fprintf(stderr, "%s: can't chanege directory to /\n", cmd);
        exit(0);
    }

    /* clsoe all open file descriptors */
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;

    for (i = 0; i < rl.rlim_max; i++)
        close(i);

    /* attach file descriptors 0, 1, and 2 to /dev/null */
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    /* initialize the log file */
    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if (fd0 != 0 || fd1 != 1 || fd2 != 2)
    {
        syslog(LOG_ERR, "unexpected file descriptors %d %d %d", 
            fd0, fd1, fd2);
        exit(1);
    }
    syslog(LOG_ERR, "hello daemon!");
}

int main(int argc, char const* argv[])
{
    daemonize("daemon test");

    pause();
    return 0;
}
